package com.meilai.project.service.personnel.onTurn.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.dto.personnel.onTurn.*;
import com.meilai.project.dto.workflow.FlowBusinessDataSuperEntity;
import com.meilai.project.dto.workflow.WorkFlowCheckDTO;
import com.meilai.project.entity.personnel.onTurn.TransferApply;
import com.meilai.project.entity.personnel.onTurn.TransferApplyNewDep;
import com.meilai.project.entity.personnel.onTurn.TransferApplyOldDep;
import com.meilai.project.entity.personnel.org.Roster;
import com.meilai.project.entity.system.UserDepartmentRelation;
import com.meilai.project.exception.CommonException;
import com.meilai.project.mapper.personnel.onTurn.TransferApplyMapper;
import com.meilai.project.service.personnel.onTurn.TransferApplyNewDepService;
import com.meilai.project.service.personnel.onTurn.TransferApplyOldDepService;
import com.meilai.project.service.personnel.onTurn.TransferApplyService;
import com.meilai.project.service.personnel.org.RosterService;
import com.meilai.project.service.system.UserDepartmentRelationService;
import com.meilai.project.service.system.impl.UserServiceImpl;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.util.WorkFlowUtil;
import com.meilai.project.vo.personnel.onTurn.TransferApplyVO;
import com.meilai.project.vo.system.UserForWFVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 异动申请 服务实现类
 * </p>
 *
 * @author xchen
 * @since 2022-01-26
 */
@Service
public class TransferApplyServiceImpl extends ServiceImpl<TransferApplyMapper, TransferApply> implements TransferApplyService {

    @Autowired
    private RosterService rosterService;

    @Autowired
    private TransferApplyOldDepService oldDepService;

    @Autowired
    private TransferApplyNewDepService newDepService;

    @Autowired
    private UserDepartmentRelationService userDepartmentRelationService;


    @Override
    public Page<TransferApplyVO> selectPageList(TransferApplyListDTO searchDTO) {
        searchDTO.addOrderItem(TransferApplyVO.ROSTER_ID,true);
        Page<TransferApplyVO> page = searchDTO.createPage(TransferApplyVO.class);
        List<TransferApplyVO> transferApplyVOS = getBaseMapper().selectPageList(page, searchDTO);
        List<Long> ids = transferApplyVOS.stream().map(TransferApplyVO::getId).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(ids)) {
            List<TransferApplyOldDep> transferApplyOldDeps = oldDepService.listByIds(ids);
            List<TransferApplyNewDep> transferApplyNewDeps = newDepService.listByIds(ids);
            Map<Long, List<TransferApplyNewDep>> newListMap = transferApplyNewDeps.stream().collect(Collectors.groupingBy(TransferApplyNewDep::getPid));
            Map<Long, List<TransferApplyOldDep>> oldListMap = transferApplyOldDeps.stream().collect(Collectors.groupingBy(TransferApplyOldDep::getPid));
            for (TransferApplyVO transferApplyVO : transferApplyVOS) {
                Long pId = transferApplyVO.getId();
                transferApplyVO.setNew_dept_list(TransferApplyDeptDTO.parseNew(newListMap.get(pId)));
                transferApplyVO.setOld_dept_list(TransferApplyDeptDTO.parseOld(oldListMap.get(pId)));
            }
        }
        page.setRecords(transferApplyVOS);
        return page;
    }

    @Override
    public TransferApplyVO getOneById(Long id) {
        TransferApplyVO result = baseMapper.queryDetailById(id);
        if(result == null) throw new CommonException("数据不存在！");
        Long userId = ThreadLocalUserUtil.get().getId();
        Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
        result.setCan_check(canCheck);
        result.setIs_applyer(userId.equals(result.getFlow_applyer_id()));

        QueryWrapper<TransferApplyNewDep> newDepQueryWrapper = new QueryWrapper<>();
        newDepQueryWrapper.eq(TransferApplyNewDep.PID,id);
        List<TransferApplyNewDep> newList = newDepService.list(newDepQueryWrapper);
        result.setNew_dept_list(TransferApplyDeptDTO.parseNew(newList));

        QueryWrapper<TransferApplyOldDep> oldDepQueryWrapper = new QueryWrapper<>();
        oldDepQueryWrapper.eq(TransferApplyOldDep.PID,id);
        List<TransferApplyOldDep> oldList = oldDepService.list(oldDepQueryWrapper);
        result.setOld_dept_list(TransferApplyDeptDTO.parseOld(oldList));

        return result;
    }

    @Override
    public TransferApplyVO getOneByIdNew(Long id, Long roster_id) {
        TransferApplyVO result = new TransferApplyVO();
        if(id == null) return result;
        result = baseMapper.queryDetailByIdNew(id, roster_id);
        if(result == null) throw new CommonException("数据不存在！");
        Long userId = ThreadLocalUserUtil.get().getId();
        Boolean canCheck = WorkFlowUtil.canCheckData(userId, result);
        result.setCan_check(canCheck);
        result.setIs_applyer(userId.equals(result.getFlow_applyer_id()));

        QueryWrapper<TransferApplyNewDep> newDepQueryWrapper = new QueryWrapper<>();
        newDepQueryWrapper.eq(TransferApplyNewDep.PID,id);
        List<TransferApplyNewDep> newList = newDepService.list(newDepQueryWrapper);
        result.setNew_dept_list(TransferApplyDeptDTO.parseNew(newList));

        QueryWrapper<TransferApplyOldDep> oldDepQueryWrapper = new QueryWrapper<>();
        oldDepQueryWrapper.eq(TransferApplyOldDep.PID,id);
        List<TransferApplyOldDep> oldList = oldDepService.list(oldDepQueryWrapper);
        result.setOld_dept_list(TransferApplyDeptDTO.parseOld(oldList));

        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean save(TransferApplyDTO dto) {
        int flowResult = saveAndBegin(dto, true);
        if (flowResult != 1) throw new CommonException("保存至草稿箱失败，请联系管理员！");
        else return true;
    }

    public int saveAndBegin(TransferApplyDTO dto, boolean isSave) {
        // 获取当前人的id和部门id
        UserForWFVO user = UserServiceImpl.getUserForWF(dto);
        TransferApply temp = new TransferApply();
        BeanUtils.copyProperties(dto, temp);

        // 设置流程字段，flow_type请自行对应“dict_flow_type”表中的id， 比如当前入职流程（考察登记流程）的id是5
        String flow_title = "调岗申请"; // 审批流程的名称，需要根据实际业务自行确定
        FlowBusinessDataSuperEntity fbdse = WorkFlowUtil.getStartSuperDataEntity(
                user.getUser_id(),  // 当前用户id
                user.getDep_id(), // 提交的部门id
                9, // 流程类型id，“dict_flow_type”表中的id
                flow_title // 自定义的流程标题
        );
        BeanUtils.copyProperties(fbdse, temp);

        // 是否为新数据
        // 新数据时，前端不传业务数据id
        // 非新数据时，即来源是“草稿箱”、“已删除”、“被退回”时，前端需要传入业务数据id
        boolean isFirst = (dto.getId() == null);

        // 由于流程字段含有id，会覆盖数据，此处需要手动setId
        if (!isFirst){
            temp.setId(dto.getId());
            //清理从表数据
            newDepService.deleteByPid(dto.getId());
            oldDepService.deleteByPid(dto.getId());
        }

        // 新增或更新业务数据
        boolean flag = isFirst ? save(temp) : updateById(temp);
        if (!flag) throw new CommonException("保存失败");

        //处理明细
        List<TransferApplyDeptDTO> old_dept_list = dto.getOld_dept_list();
        oldDepService.saveBatch(TransferApplyDeptDTO.toOld(temp.getId(), old_dept_list));
        List<TransferApplyDeptDTO> new_dept_list = dto.getNew_dept_list();
        newDepService.saveBatch(TransferApplyDeptDTO.toNew(temp.getId(),new_dept_list));

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<TransferApply, TransferApplyMapper>(temp.getId(),
                user.getUser_id(), TransferApply.class);

        // 审批流程id
        // 新数据,传0L
        // 非新数据,根据数据id,查找wfData_id
        Long wfData_id = isFirst ? 0L : wfu.getWfDataId(dto.getId());
        // 旧数据记录留存
        TransferApply old_data = isFirst ? new TransferApply() : temp;

        return isSave ? wfu.SaveDraft(wfData_id) : wfu.Begin(wfData_id, "", old_data);
    }

    // 通过 和 驳回 抽出相同代码
    private int passAndBack(TransferApplyCheckDTO dto, boolean isPass, boolean... updateData) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 若业务数据有审批中可修改的内容，请自行更新
        if (updateData != null && updateData[0]) {
            TransferApply updateTemp = new TransferApply();
            BeanUtils.copyProperties(dto, updateTemp);
            updateById(updateTemp);
        }

        // 业务数据
        TransferApply temp = getById(dto.getId());

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<TransferApply, TransferApplyMapper>(dto.getId(), userId, TransferApply.class);

        // 审批入参类
        WorkFlowCheckDTO checkDTO = WorkFlowCheckDTO.getWorkFlowCheckDTO(
                temp.getFlow_current_node_id(), // 当前节点id
                temp.getFlow_json(), // 流程json
                dto.getWf_check_opinion(), // 审批意见
                dto.getWf_check_sign_url(), // 审批签名链接
                JSONObject.toJSONString(temp) // 旧数据留存
        );

        // 审批
        return isPass ? wfu.ToNext(checkDTO) : wfu.ReturnBack(checkDTO);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean begin(TransferApplyDTO dto) {
        // 提交
        int flowResult = saveAndBegin(dto, false);
        if (flowResult == 1) {
            // 仍在流程中
            return true;
        } else if (flowResult == 2) {
            // 无审批节点，直接结束
            updateUserDeptRelation(dto.getId());
            return true;
        } else {
            throw new CommonException("提交失败，请联系管理员！");
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean pass(TransferApplyCheckDTO dto) {
        // 通过
        int flowResult = passAndBack(dto, true, false);
        if (flowResult == 1) {
            // 通过后仍然在流程中
            return true;
        } else if (flowResult == 2) {
            // 审核后流程结束
            // 更新用户部门关系表
            updateUserDeptRelation(dto.getId());
            return true;
        } else {
            throw new CommonException("通过失败，请联系管理员！");
        }
    }

    private void updateUserDeptRelation(Long pId) {
        TransferApply transferApply = getById(pId);
        Roster roster = rosterService.getById(transferApply.getRoster_id());

        QueryWrapper<UserDepartmentRelation> relationQueryWrapper = new QueryWrapper<>();
        relationQueryWrapper.eq("user_id",roster.getUser_id());
        userDepartmentRelationService.remove(relationQueryWrapper);

        QueryWrapper<TransferApplyNewDep> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(TransferApplyNewDep.PID,pId);
        List<TransferApplyNewDep> list = newDepService.list(queryWrapper);
        List<UserDepartmentRelation> userDepartmentRelationList = TransferApplyNewDep.to(roster.getUser_id(),list);
        userDepartmentRelationService.saveBatch(userDepartmentRelationList);
    }





    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean returnBack(TransferApplyCheckDTO dto) {
        // 驳回
        int flowResult = passAndBack(dto, false, false);
        if (flowResult != 1) throw new CommonException("驳回失败，请联系管理员！");
        return true;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean delete(Long id) {
        int flowResult = deleteAndActualDel(id, false);
        if (flowResult != 1) throw new CommonException("删除失败，请联系管理员！");
        return true;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean actualDelete(Long id) {
        int flowResult = deleteAndActualDel(id, true);
        if (flowResult != 1) throw new CommonException("彻底删除失败，请联系管理员！");
        return true;
    }

    // 删除 和 彻底删除 抽出相同代码
    private int deleteAndActualDel(Long id, boolean isActual) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<TransferApply, TransferApplyMapper>(id, userId, TransferApply.class);

        // 流程id
        Long wfData_id = wfu.getWfDataId(id);

        return isActual ? wfu.ActualDelete(wfData_id) : wfu.Delete(wfData_id);
    }
}
